//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2006-2007
//
// Routing graph nodes.
//

# include "StdAfx.h"
# include "RGNodes.h"
# include "Globals.h"
# include "Map.h"

bool rgrestriction_t::IsUsed () const {
	if (
		pNode     != NULL &&   pNode    ->IsUsed    () &&
		pFromRoad != NULL && ! pFromRoad->IsDeleted () &&
		pToRoad   != NULL && ! pToRoad  ->IsDeleted ()
	)
		return true;

	return false;
}

bool rgrestriction_t::IsValid () const {
	if (pNode == NULL)
		return false;

	if (pFromRoad == NULL || pToRoad == NULL)
		return false;
	if (pFromRoad->IsDeleted ())
		return false;
	if (pToRoad  ->IsDeleted ())
		return false;

//	if (! bFromDirection && _IsOneWayRoad (* pFromRoad))
//		return false;
//	if (! bToDirection   && _IsOneWayRoad (* pToRoad))
//		return false;

	if (! pFromRoad->HasNode (pNode)) 
		return false;
	if (! pToRoad  ->HasNode (pNode)) 
		return false;

	return true;
}


////////////////////////////////////////////////////

void map_t::CountRGNodes (bool _bEnforce) {
	if (rgnodes.empty ())
		return;

	// Reset draw counters.
	rgnodes_t::iterator ni;
	for (ni = rgnodes.begin (); ni != rgnodes.end (); ++ ni) {
		rgnode_t & node = * ni;
		node.btDrawCount = 0;
	}

	if (! _bEnforce && ! bDirtyRGNodes)
		return;

	// Reset other counters.
	for (ni = rgnodes.begin (); ni != rgnodes.end (); ++ ni) {
		rgnode_t & node = * ni;
		node.btCardinality    = 0;
		node.btPolylines      = 0;
		node.bHasRestrictions = false;
	}

	// Re-count nodes references.
	rgns_t & polylines = g_map.layers [rkPolyline].rgns;
	for (rgns_t::iterator iRgn = polylines.begin (); iRgn != polylines.end (); ++ iRgn) {
		rgn_t & rgn = * iRgn;
		if (rgn.IsDeleted () || rgn.IsWTR ())
			continue;

		const size_t cElements = rgn.elements.size ();
		for (size_t cElement = 0; cElement < cElements; ++ cElement) {
			rgn_element_t & element = rgn.elements [cElement];
			if (element.bDeleted || element.pExtra == NULL)
				continue;

			const size_t cPoints = element.points.size ();

			point_extras_t & PointExtras = element.pExtra->PointExtras;
			const size_t cPointExtras = PointExtras.size ();
			for (size_t cPoint = 0; cPoint < cPointExtras; ++ cPoint) {
				rgnode_t * const pNode = PointExtras [cPoint].GetRGNode ();
				if (pNode) {
					++ pNode->btPolylines;

					const bool bEndNode = cPoint == 0 || cPoint + 1 == cPoints;
					PointExtras [cPoint].SetEndNode (bEndNode);
					if (bEndNode)
						++ pNode->btCardinality;
					else
						pNode->btCardinality += 2;
				}
			}
		}
	}

	// Update turn restrictions flags.
	for (rgrestrictions_t::iterator r = rgrestrictions.begin (); r != rgrestrictions.end (); ++ r) {
		rgrestriction_t & restriction = r->second;
		if (restriction.IsUsed ())
			restriction.pNode->bHasRestrictions = true;
	}

	bDirtyRGNodes = false;
}

rgnode_t & map_t::CreateNode (DWORD _dwNodeID) {
	this->rgnodes.push_back (rgnode_t ());
	rgnode_t & node = this->rgnodes.back ();
	node.dwNodeID = _dwNodeID;

	if (dwMaxNodeID < _dwNodeID)
		dwMaxNodeID = _dwNodeID;
	return node;
}

rgnode_t & map_t::CreateNode () {
	++ dwMaxNodeID;
	return CreateNode (dwMaxNodeID);
}

bool map_t::HasNode (DWORD _dwNodeID) const {
	for (rgnodes_t::const_iterator ni = rgnodes.begin (); ni != rgnodes.end (); ++ ni) {
		const rgnode_t & node = * ni;
		if (! node.IsUsed ())
			continue;
		if (node.dwNodeID == _dwNodeID)
			return true;
	}
	return false;
}

rgnode_t * map_t::FindExternalNode (const point_t & _pt) {
	layer_t & layer = layers[rkPolyline];
	for (rgns_t::iterator ri = layer.rgns.begin (); ri != layer.rgns.end (); ++ ri) {
		rgn_t & rgn = * ri;
		for (rgn_elements_t::iterator ei = rgn.elements.begin (); ei != rgn.elements.end (); ++ ei) {
			rgn_element_t & element = * ei;
			if (!element.pExtra)
				continue;
			const double c_fE = 360.f/(1 << Levels [element.cLevel].btBits); 
			const points_t & points = element.points;
			point_extras_t & extras = element.pExtra->PointExtras;
			const size_t cPoints = __min (extras.size (), points.size ());
			for (size_t cPoint = 0; cPoint < cPoints; ++ cPoint) {
				const rgnode_t * const pRGNode = extras [cPoint].GetRGNode ();
				if (pRGNode == NULL)
					continue;
				if (! pRGNode->bIsExternal)
					continue;

				const point_t & point = points [cPoint];

				if (PointContainsPt (point, _pt, c_fE, g_map.fCosY))
					return extras[cPoint].GetRGNode ();
			}
		}
	}
	return NULL;
}

void map_t::MakeSureAllNodeIDsAreUnique () {
	std::set<DWORD> NodeIDs;
	for (rgnodes_t::iterator ni = rgnodes.begin (); ni != rgnodes.end (); ++ ni) {
		rgnode_t & node = * ni;
		if (! node.IsUsed ())
			continue;

		while (true) {
			if (NodeIDs.find (node.dwNodeID) == NodeIDs.end ()) {
				NodeIDs.insert (node.dwNodeID);
				break;
			}

			++ dwMaxNodeID;
			node.dwNodeID = dwMaxNodeID;
		}
	}
}

const rgnode_t * GetRGNode (const rgn_t & _rgn, size_t _cElement, size_t _cPoint) {
	const rgn_element_t & element = _rgn.elements [_cElement];
	if (element.pExtra && _cPoint < element.pExtra->PointExtras.size ())
		return element.pExtra->PointExtras [_cPoint].GetRGNode ();
	else
		return NULL;
}

rgnode_t * GetRGNode (rgn_t & _rgn, size_t _cElement, size_t _cPoint) {
	rgn_element_t & element = _rgn.elements [_cElement];
	if (element.pExtra && _cPoint < element.pExtra->PointExtras.size ())
		return element.pExtra->PointExtras [_cPoint].GetRGNode ();
	else
		return NULL;
}

//////////////////////////////////

rgrestriction_t & AddRGNodeRestriction (map_t & _map, rgnode_t * _pNode) {
	assert (_pNode != NULL);

	const rgrestrictions_t::iterator i = _map.rgrestrictions.insert (rgrestrictions_t::value_type (_pNode, rgrestriction_t ()));
	rgrestriction_t & restriction = i->second;
	restriction.pNode = _pNode;
	return restriction;
}

rgrestrictions_t::iterator FindRGNodeRestriction (rgrestrictions_t & _rgrestrictions, const rgrestriction_t & _restriction) {
	typedef std::pair<rgrestrictions_t::iterator, rgrestrictions_t::iterator> rr_t;
	const rr_t rr = _rgrestrictions.equal_range (_restriction.pNode);

	for (rgrestrictions_t::iterator ir = rr.first; ir != rr.second; ++ ir) {
		if (& ir->second == & _restriction)
			return ir;
	}

	return _rgrestrictions.end ();
}


